package cn.z2huo.productcenter.util;

import cn.hutool.crypto.digest.DigestUtil;
import cn.z2huo.productcenter.constant.SystemConstants;
import cn.z2huo.productcenter.enums.AppEnum;
import cn.z2huo.productcenter.enums.SystemEnum;
import cn.z2huo.productcenter.jackson.RedisJsonMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.json.JsonMapper;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

/**
 * 生成的 Key 应该小于等于 44 位
 * 分为三部分，由冒号分隔，三部分都为 MD5 串，三部分长度分别为：8 位、16 位、16 位
 * 第一部分表示系统和应用标识：系统编码 + 冒号 + 应用编码，例如：product-center:00009002 或 product-center:product-management-app
 * 第二部分表示资源类型和业务代码：资源类型 + 冒号 + 业务代码，例如：user:11001100 或 risk:risc81ee4cd150b8ae4
 * 第三部分为扩展部分，内容可以为缓存方法入参、空字符串等
 *
 * @author z2huo
 */
@RequiredArgsConstructor
public enum RedisKeyGenerateUtils {

    /**
     * <p>默认
     * <p>appCode 字段为空，表示 key 可能为多个 app 共用
     */
    DEFAULT(SystemConstants.CURRENT_SYSTEM, null),

    MANAGEMENT_APP(SystemConstants.CURRENT_SYSTEM, AppEnum.MANAGEMENT_APP),

    MANAGEMENT_CLIENT(SystemConstants.CURRENT_SYSTEM, AppEnum.MANAGEMENT_CLIENT),

    CATALOG_APP(SystemConstants.CURRENT_SYSTEM, AppEnum.CATALOG_APP),

    ;

    private final SystemEnum system;

    private final AppEnum app;

    private static final JsonMapper CACHE_JSON_MAPPER = RedisJsonMapper.INSTANCE;

    @Deprecated
    public String generate(String resourceType, String resourceCode, Object... others) {
        return generate(system, app, resourceType, resourceCode, others);
    }

    @Deprecated
    public static String generate(@Nonnull SystemEnum systemCode, @Nullable AppEnum appCode, @Nonnull String resourceType,
                                  @Nullable String resourceCode, @Nullable Object... others) {
        String md5ParameterString = "";
        if (ArrayUtils.isNotEmpty(others)) {
            try {
                md5ParameterString = DigestUtil.md5Hex16(CACHE_JSON_MAPPER.writeValueAsBytes(others));
            } catch (JsonProcessingException e) {
                throw new RuntimeException("generate redis key fail", e);
            }
        }
        return String.format("%s:%s:%s:%s:%s", systemCode, appCode, resourceType, resourceCode, md5ParameterString);
    }

    public String generateMd5(@Nonnull String resourceType, @Nullable String resourceCode, @Nullable Object... others) {
        return generateMd5(system, app, resourceType, resourceCode, others);
    }

    public static String generateMd5(@Nonnull SystemEnum systemCode, @Nullable AppEnum appCode, @Nonnull String resourceType,
                                     @Nullable String resourceCode, @Nullable Object... others) {
        String md5ParameterString = "";
        if (ArrayUtils.isNotEmpty(others)) {
            try {
                md5ParameterString = DigestUtil.md5Hex16(CACHE_JSON_MAPPER.writeValueAsBytes(others));
            } catch (JsonProcessingException e) {
                throw new RuntimeException("generate redis key fail", e);
            }
        }
        return String.format("%s:%s:%s",
                DigestUtil.md5Hex(appCode == null ? systemCode.getSystemCode() : systemCode + ":" + appCode.getAppCode()).substring(0, 8),
                DigestUtil.md5Hex16(StringUtils.isBlank(resourceCode) ? resourceType : resourceType + ":" + resourceCode),
                md5ParameterString);
    }

}
